#ifndef MOONGENERATOR_H_
#define MOONGENERATOR_H_

#include <string>
#include <vector>
#include <fstream>

#include "Interfaces.h"
#include "ThreeAddressCode.h"

#define REG_BASE	 	"R1"
#define REG_RET_ADDR	"R15"
#define REG_FSIZE		"R14"
#define REG_GENP_1		"R2"
#define REG_GENP_2		"R3"
#define REG_GENP_3		"R4"
#define REG_GENP_4		"R5"
#define REG_GENP_5		"R6"
#define REG_GENP_6		"R7"
#define REG_GENP_7		"R8"

#define ADDR_OLD_RET_ADDR 	0
#define ADDR_OLD_BASE	  	4
#define ADDR_OLD_FSIZE		8
#define ADDR_RET_VAL		12

#define CONST_BOOKEEPING_SZ	16
#define CONST_WORD_SZ		4

class TargetCodeGenerator
{
public:
	virtual void generateTargetCode() =0;
	virtual void setNumericalConsts(std::string numConsts) =0;
	virtual void setCharacterConsts(std::string charConsts) =0;
};

class MoonGenerator : public TargetCodeGenerator
{
public:
	MoonGenerator(std::string outputFile, TCodeInterface* iCodeRep);
	virtual ~MoonGenerator();
	
	void generateTargetCode();
	void setNumericalConsts(std::string numConsts);
	void setCharacterConsts(std::string charConsts);
		
private:
	int paramCount;
	std::ofstream outputFile;
	TCodeInterface* iCode;
	
	std::string numericalConstants;
	std::string characterConstants;
	
	static std::string arithmeticOperators[TAC_OR-TAC_MULT+2];
	
	void initTargetCode(std::string filename);
	void convertIntermediateCode(const ThreeAddressCode* tac);
	
	bool isArithmeticOperator(OpCode op);
	std::string getMoonArithmeticOperator(OpCode op);
	
	void saveResult(
			const ThreeAddressCode* tac, 
			std::string sourceRegister,
			std::string unusedRegister = REG_GENP_7);
	void loadOperand1(const ThreeAddressCode* tac, std::string targetRegister);
	void loadOperand2(const ThreeAddressCode* tac, std::string targetRegister);
};

#endif /*MOONGENERATOR_H_*/
